module ResultsetAutofilter

  class Sharedance
  # Copyright (c) 2007 Frank Denis <ruby@pureftpd.org>  under MIT license
    require 'socket'
    require 'timeout'

    SHAREDANCE_DEFAULT_PORT = 1042
    SHAREDANCE_DEFAULT_TIMEOUT = 10
    attr_accessor :host, :port, :timeout

    def initialize(params)
      @host = params[:host]
      @port = params[:port] || SHAREDANCE_DEFAULT_PORT
      @timeout = params[:timeout] || SHAREDANCE_DEFAULT_TIMEOUT
    end


  
    def self.open(params)
      yield(self.new(params))
    end
  
    def fetch(params)
      result = sharedance_command(
        "F" + params[:key].encode_size_for_sharedance + params[:key]) do
        @sock.read
      end
      result.empty? ? nil : result
    end
    
    def store(params)
      sharedance_command(
        "S" + params[:key].encode_size_for_sharedance +
              params[:data].encode_size_for_sharedance +
              params[:key] + params[:data]) do
        raise "Storage failed" unless @sock.read === "OK\n"
      end
    end
    
    def delete(params)
      sharedance_command(
        "D" + params[:key].encode_size_for_sharedance + params[:key]) do
        raise "Deletion failed" unless @sock.read === "OK\n"
      end
    end
    
    def [](key)
      fetch(:key => key)
    end
    
    def []=(key, data)
      if data.nil?
        delete(:key => key)
      else
        store(:key => key, :data => data)
      end
    end
    
  protected
    @sock = nil
  
    def connect_to_server
      @sock = TCPSocket.new(@host, @port) unless @sock
    end
  
    def close_from_server
      @sock.close if @sock
      @sock = nil
    end
  
    def sharedance_command(command)
      result = nil  
      begin
        Timeout.timeout(@timeout) do
          connect_to_server
          @sock << command
          result = yield
        end
      ensure
        close_from_server
      end
      result    
    end
  end
  

end